package org.lex.swing.widgets;

import java.awt.Component;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.Stack;

import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import org.lex.swing.Swings;
import org.lex.utils.collections.Collections;


public class NetworkInterfaceTree extends JTree {
	private DefaultMutableTreeNode root = null;

	public static void main(String[] args) {
		Swings.setUseBoldMetalFont(false);
		Swings.show(new NetworkInterfaceTree(), false);
	}

	public NetworkInterfaceTree() {
		super();
		initialize();
	}

	/**
	 * 
	 * @return selected NetworkInterface, or null if selection is empty
	 */
	public NetworkInterface getSelectedNetworkInterface() {
		TreePath path = this.getSelectionPath();
		if (null == path)
			return null;
		DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
		if (null == node || node == this.getTreeRootNode())
			return null;
		return (NetworkInterface) node.getUserObject();
	}

	private void initialize() {
		this.setModel(new DefaultTreeModel(this.getTreeRootNode()));
		this.setCellRenderer(new TreeNodeRenderer());
	}

	private TreeNode getTreeRootNode() {
		if (null == root) {
			root = new DefaultMutableTreeNode("Root");
			this.addInterfaces(root, this.getAllNetworkInterfaces());
			// add sub-networkinterface
			Stack<DefaultMutableTreeNode> stack = new Stack<DefaultMutableTreeNode>();
			addEnumerationToStack(stack, root.children());
			while (false == stack.isEmpty()) {
				DefaultMutableTreeNode node = stack.pop();
				NetworkInterface ni = (NetworkInterface) node.getUserObject();
				int counter = this.addInterfaces(node, ni.getSubInterfaces());
				if (counter != 0)
					addEnumerationToStack(stack, node.children());
			}
		}
		return root;
	}

	private int addInterfaces(DefaultMutableTreeNode parent, Enumeration<NetworkInterface> ni) {
		if (ni == null)
			return 0;
		int counter = 0;
		while (ni.hasMoreElements()) {
			parent.add(new DefaultMutableTreeNode(ni.nextElement()));
			counter++;
		}
		return counter;
	}

	private <T> int addEnumerationToStack(Stack<T> stack, Enumeration<T> e) {
		if (null == e)
			return 0;
		int counter = 0;
		while (e.hasMoreElements()) {
			stack.push(e.nextElement());
			counter++;
		}
		return counter;
	}

	private Enumeration<NetworkInterface> getAllNetworkInterfaces() {
		Enumeration<NetworkInterface> nis = null;
		try {
			nis = NetworkInterface.getNetworkInterfaces();
		} catch (SocketException e) {
			e.printStackTrace();
			nis = Collections.emptyEnumeration();
		}
		return nis;
	}

	class TreeNodeRenderer extends DefaultTreeCellRenderer {
		public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
			String text = null;
			if (value == getTreeRootNode()) {
				text = "Network Interfaces";
			} else {
				DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
				NetworkInterface ni = (NetworkInterface) node.getUserObject();
				text = ni.getName();
			}
			return super.getTreeCellRendererComponent(tree, text, sel, expanded, leaf, row, hasFocus);
		}
	}
}
